#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

#define portbase 1024

int
connectsock (const char *host, const char *service, const char *transport)
{
  struct hostent *phe;
  struct servent *pse;
  struct protoent *ppe;
  struct sockaddr_in sin;
  int s, type;
  memset (&sin, 0, sizeof (sin));
  sin.sin_family = AF_INET;
  /* Map service name to port number */
  if (pse = getservbyname (service, transport))
    sin.sin_port = pse->s_port;
  else if ((sin.sin_port = htons ((u_short) atoi (service))) == 0)
    printf ("can't get \"%s\" service entry\n", service);
  /* Map host name to IP address, allowing for dotted decimal */
  if (phe = gethostbyname (host))
    memcpy (&sin.sin_addr, phe->h_addr, phe->h_length);
  else if ((sin.sin_addr.s_addr = inet_addr (host)) == INADDR_NONE)
    printf ("can't get \"%s\" host entry\n", host);
  /* Use protocol to choose a socket type */
  if (strcmp (transport, "udp") == 0)
    type = SOCK_DGRAM;
  else
    type = SOCK_STREAM;
  /* Allcoate a socket */
  s = socket (PF_INET, type, ppe->p_proto);
  if (s < 0)
    printf ("can't create socket: %s\n", strerror (errno));
  /* Connect the socket */
  if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
    printf ("can't connect to %s.%s: %s\n", host, service, strerror (errno));
  return s;
}

int
passivesock (const char *service, const char *transport, int qlen)
{
  struct servent *pse;
  struct protoent *ppe;
  struct sockaddr_in sin;
  int s, type;
  memset (&sin, 0, sizeof (sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = INADDR_ANY;
  /* Map service name to port number */
  if (pse = getservbyname (service, transport))
    sin.sin_port = htons (ntohs ((u_short) pse->s_port) + portbase);
  else if ((sin.sin_port = htons ((u_short) atoi (service))) == 0)
    printf ("can't get \"%s\" service entry\n", service);
  /* Map protocol name to protocol number */
/*  if ((ppe = getprotobyname (transport)) == 0)
    printf ("can't get \"%s\" protocol entry\n", transport);
   Use protocol to choose a socket type */
  if (strcmp (transport, "udp") == 0 || strcmp(transport, "UDP") == 0)
    type = SOCK_DGRAM;
  else
    type = SOCK_STREAM;
  /* Allocate a socket */
  //s = socket (PF_INET, type, ppe->p_proto);
  s = socket (PF_INET, type, 0);
  if (s < 0)
    printf ("can't create socket: %s\n", strerror (errno));
  /* Bind the socket */
  if (bind (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
    printf ("can't bind to %s port: %s\n", service, strerror (errno));
  if (type == SOCK_STREAM && listen (s, qlen) < 0)
    printf ("can't listen on %s port: %s\n", service, strerror (errno));
  return s;
}

int
connectTCP (const char *host, const char *service)
{
  return connectsock (host, service, "TCP");
}

int
connectUDP (const char *host, const char *service)
{
  return connectsock (host, service, "UDP");
}

int
passiveUDP (const char *service)
{
  return passivesock (service, "UDP", 0);
}

int
passiveTCP (const char *service, int qlen)
{
  return passivesock (service, "TCP", qlen);
}
